package com.mojo.jedis.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.DefaultBaseTypeLimitingValidator;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.integration.redis.util.RedisLockRegistry;

import java.time.Duration;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;

/**
* redis配置
*
* @author <a href="mailto:sjj@jianzhimao.com">mojo</a>
* copyright (C), 2013-2021, 广州九尾信息科技有限公司
* @date 2021/9/26 10:06
*/
@Configuration
public class RedisConfig {
   @Bean
   public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
       RedisTemplate<String, Object> template = new RedisTemplate<>();
       template.setConnectionFactory(factory);
       // GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
       // Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
       Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = getJackson2JsonRedisSerializer();
       StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
       // key采用String的序列化方式
       template.setKeySerializer(stringRedisSerializer);
       // hash的key也采用String的序列化方式
       template.setHashKeySerializer(stringRedisSerializer);
       // value序列化方式采用jackson
       template.setValueSerializer(jackson2JsonRedisSerializer);
       // hash的value序列化方式采用jackson
       template.setHashValueSerializer(jackson2JsonRedisSerializer);
       template.afterPropertiesSet();
       template.setEnableTransactionSupport(true);
       return template;
   }

   private Jackson2JsonRedisSerializer<Object> getJackson2JsonRedisSerializer() {
       Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
       ObjectMapper objectMapper = new ObjectMapper();
       // 处理日期和时间序列化为标准格式
       objectMapper.registerModule(new JavaTimeModule());
       // objectMapper.activateDefaultTyping(new DefaultBaseTypeLimitingValidator());
       objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(),ObjectMapper.DefaultTyping.NON_FINAL);
       // 时间戳序列化
       objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
       objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
       objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
       // 设置验证器,序列化时保存对象全类名
       // objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
       serializer.setObjectMapper(objectMapper);
       return serializer;
   }

   @Bean
   public CacheManager cacheManager(RedisConnectionFactory factory) {
       RedisSerializer<String> redisSerializer = new StringRedisSerializer();
       // 配置序列化（解决乱码的问题）
       RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
               // 缓存有效期
               // .entryTtl(Duration.ofDays(1))
               // 使用StringRedisSerializer来序列化和反序列化redis的key值
               .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
               // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
               .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(getJackson2JsonRedisSerializer()))
               // 禁用空值
               .disableCachingNullValues();

       return RedisCacheManager.builder(factory).cacheDefaults(config).build();
   }

   @Bean(destroyMethod = "destroy")
   public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
       return new RedisLockRegistry(redisConnectionFactory, "lock");
   }
}
